Imports System.IO
Imports System.Text
Imports System.Security.Cryptography

Public Class Encryption
    Enum CryptFunction
        encrypt = 1
        decrypt = 2
    End Enum

    Private Shared DoOAEPPadding As Boolean = False 'OAEP padding is only available on Microsoft Windows XP or later. 

    Public Shared Function aesCrypt(ByVal inFile As String, ByVal outFile As String, ByRef key As Byte(), ByVal operation As CryptFunction) As Boolean
        Try
            Dim fIn As New FileStream(inFile, FileMode.Open, FileAccess.Read)
            Dim fOut As New FileStream(outFile, FileMode.OpenOrCreate, FileAccess.Write)
            fOut.SetLength(0)

            Dim aes As New RijndaelManaged
            aes.KeySize = 256
            aes.BlockSize = 256
            aes.Mode = CipherMode.CBC
            aes.Padding = PaddingMode.PKCS7
            aes.GenerateKey()
            aes.GenerateIV()

            Dim crStream As CryptoStream
            If (operation = CryptFunction.encrypt) Then
                key = aes.Key
                Dim iv As Byte() = aes.IV
                Array.ConstrainedCopy(key, 0, iv, 0, iv.Length)
                crStream = New CryptoStream(fOut, aes.CreateEncryptor(key, iv), CryptoStreamMode.Write)
            Else
                aes.Key = key
                Dim iv As Byte() = aes.IV
                Array.ConstrainedCopy(key, 0, iv, 0, iv.Length)
                crStream = New CryptoStream(fOut, aes.CreateDecryptor(key, iv), CryptoStreamMode.Write)
            End If

            Dim buffer(4096) As Byte
            Dim bytesDone As Long = 0
            Dim bytesTotal As Long = fIn.Length
            Dim bytesInCur As Integer

            While bytesDone < bytesTotal
                bytesInCur = fIn.Read(buffer, 0, 4096)
                crStream.Write(buffer, 0, bytesInCur)
                bytesDone += CLng(bytesInCur)
            End While

            crStream.Close()
            fIn.Close()
            fOut.Close()
            Return True
        Catch e As Exception
            MsgBox("aes: " & e.Message & vbNewLine & e.StackTrace)
        End Try
        Return False
    End Function

    Public Shared Sub generateRsaKeys(ByRef publicKey() As Byte, ByRef privateKey() As Byte)
        Dim rsa As New RSACryptoServiceProvider
        publicKey = rsa.ExportCspBlob(False)
        privateKey = rsa.ExportCspBlob(True)
    End Sub

    Public Shared Function rsaEncrypt(ByVal data() As Byte, ByVal publicKey() As Byte) As Byte()
        Dim rsa As New RSACryptoServiceProvider
        rsa.ImportCspBlob(publicKey)
        Return rsa.Encrypt(data, DoOAEPPadding)
    End Function

    Public Shared Function rsaDecrypt(ByVal data() As Byte, ByVal privateKey() As Byte) As Byte()
        Dim rsa As New RSACryptoServiceProvider
        rsa.ImportCspBlob(privateKey)
        Return rsa.Decrypt(data, DoOAEPPadding)
    End Function

    Public Shared Function rsaCheckKeys(ByVal publicKey() As Byte, ByVal privateKey() As Byte) As Boolean
        If publicKey Is Nothing Then Return False
        If privateKey Is Nothing Then Return False

        Dim rsa As New RSACryptoServiceProvider
        rsa.ImportCspBlob(publicKey)
        Dim pub As RSAParameters = rsa.ExportParameters(False)
        rsa.ImportCspBlob(privateKey)
        Dim pri As RSAParameters = rsa.ExportParameters(True)

        If Not isEqual(pub.Exponent, pri.Exponent) Then Return False
        If Not isEqual(pub.Modulus, pri.Modulus) Then Return False
        Return True
    End Function

    Public Shared Function isEqual(ByVal a() As Byte, ByVal b() As Byte) As Boolean
        If Not a.Length = b.Length Then Return False
        For i As Integer = 0 To a.Length - 1
            If Not a(i) = b(i) Then Return False
        Next
        Return True
    End Function

    Public Shared Function concatBytes(ByVal a() As Byte, ByVal b() As Byte) As Byte()
        Dim bytes(a.Length + b.Length - 1) As Byte
        Array.Copy(a, 0, bytes, 0, a.Length)
        Array.Copy(b, 0, bytes, a.Length, b.Length)
        Return bytes
    End Function

    Public Shared Function hashPassword(ByVal password As String, ByVal salt() As Byte) As String
        Dim enc As New UnicodeEncoding
        Dim hashFunc As New SHA512Managed
        Return Convert.ToBase64String(hashFunc.ComputeHash(concatBytes(salt, enc.GetBytes(password))))
    End Function

    Public Shared Function generateSalt() As Byte()
        Dim rng As New RNGCryptoServiceProvider()
        Dim salt(32) As Byte
        rng.GetBytes(salt)
        Return salt
    End Function
End Class